// XRegExp 1.5.1
// (c) 2007-2012 Steven Levithan
// MIT License
// <http://xregexp.com>
// Provides an augmented, extensible, cross-browser implementation of regular expressions,
// including support for additional syntax, flags, and methods

var XRegExp;

if (XRegExp) {
	// Avoid running twice, since that would break references to native globals
	throw Error("can't load XRegExp twice in the same frame");
}

// Run within an anonymous function to protect variables and avoid new globals
(function(undefined) {

	// ---------------------------------
	// Constructor
	// ---------------------------------

	// Accepts a pattern and flags; returns a new, extended `RegExp` object.
	// Differs from a native
	// regular expression in that additional syntax and flags are supported and
	// cross-browser
	// syntax inconsistencies are ameliorated. `XRegExp(/regex/)` clones an
	// existing regex and
	// converts to type XRegExp
	XRegExp = function(pattern, flags) {
		var output = [], currScope = XRegExp.OUTSIDE_CLASS, pos = 0, context, tokenResult, match, chr, regex;

		if (XRegExp.isRegExp(pattern)) {
			if (flags !== undefined)
				throw TypeError("can't supply flags when constructing one RegExp from another");
			return clone(pattern);
		}
		// Tokens become part of the regex construction process, so protect
		// against infinite
		// recursion when an XRegExp is constructed within a token handler or
		// trigger
		if (isInsideConstructor)
			throw Error("can't call the XRegExp constructor within token definition functions");

		flags = flags || "";
		context = { // `this` object for custom tokens
			hasNamedCapture : false,
			captureNames : [],
			hasFlag : function(flag) {
				return flags.indexOf(flag) > -1;
			},
			setFlag : function(flag) {
				flags += flag;
			}
		};

		while (pos < pattern.length) {
			// Check for custom tokens at the current position
			tokenResult = runTokens(pattern, pos, currScope, context);

			if (tokenResult) {
				output.push(tokenResult.output);
				pos += (tokenResult.match[0].length || 1);
			} else {
				// Check for native multicharacter metasequences (excluding
				// character classes) at
				// the current position
				if (match = nativ.exec.call(nativeTokens[currScope], pattern
						.slice(pos))) {
					output.push(match[0]);
					pos += match[0].length;
				} else {
					chr = pattern.charAt(pos);
					if (chr === "[")
						currScope = XRegExp.INSIDE_CLASS;
					else if (chr === "]")
						currScope = XRegExp.OUTSIDE_CLASS;
					// Advance position one character
					output.push(chr);
					pos++;
				}
			}
		}

		regex = RegExp(output.join(""), nativ.replace.call(flags, flagClip, ""));
		regex._xregexp = {
			source : pattern,
			captureNames : context.hasNamedCapture ? context.captureNames
					: null
		};
		return regex;
	};

	// ---------------------------------
	// Public properties
	// ---------------------------------

	XRegExp.version = "1.5.1";

	// Token scope bitflags
	XRegExp.INSIDE_CLASS = 1;
	XRegExp.OUTSIDE_CLASS = 2;

	// ---------------------------------
	// Private variables
	// ---------------------------------

	var replacementToken = /\$(?:(\d\d?|[$&`'])|{([$\w]+)})/g, flagClip = /[^gimy]+|([\s\S])(?=[\s\S]*\1)/g, // Nonnative
																												// and
																												// duplicate
																												// flags
	quantifier = /^(?:[?*+]|{\d+(?:,\d*)?})\??/, isInsideConstructor = false, tokens = [],
	// Copy native globals for reference ("native" is an ES3 reserved keyword)
	nativ = {
		exec : RegExp.prototype.exec,
		test : RegExp.prototype.test,
		match : String.prototype.match,
		replace : String.prototype.replace,
		split : String.prototype.split
	}, compliantExecNpcg = nativ.exec.call(/()??/, "")[1] === undefined, // check
																			// `exec`
																			// handling
																			// of
																			// nonparticipating
																			// capturing
																			// groups
	compliantLastIndexIncrement = function() {
		var x = /^/g;
		nativ.test.call(x, "");
		return !x.lastIndex;
	}(), hasNativeY = RegExp.prototype.sticky !== undefined, nativeTokens = {};

	// `nativeTokens` match native multicharacter metasequences only (including
	// deprecated octals,
	// excluding character classes)
	nativeTokens[XRegExp.INSIDE_CLASS] = /^(?:\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S]))/;
	nativeTokens[XRegExp.OUTSIDE_CLASS] = /^(?:\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S])|\(\?[:=!]|[?*+]\?|{\d+(?:,\d*)?}\??)/;

	// ---------------------------------
	// Public methods
	// ---------------------------------

	// Lets you extend or change XRegExp syntax and create custom flags. This is
	// used internally by
	// the XRegExp library and can be used to create XRegExp plugins. This
	// function is intended for
	// users with advanced knowledge of JavaScript's regular expression syntax
	// and behavior. It can
	// be disabled by `XRegExp.freezeTokens`
	XRegExp.addToken = function(regex, handler, scope, trigger) {
		tokens.push({
			pattern : clone(regex, "g" + (hasNativeY ? "y" : "")),
			handler : handler,
			scope : scope || XRegExp.OUTSIDE_CLASS,
			trigger : trigger || null
		});
	};

	// Accepts a pattern and flags; returns an extended `RegExp` object. If the
	// pattern and flag
	// combination has previously been cached, the cached copy is returned;
	// otherwise the newly
	// created regex is cached
	XRegExp.cache = function(pattern, flags) {
		var key = pattern + "/" + (flags || "");
		return XRegExp.cache[key]
				|| (XRegExp.cache[key] = XRegExp(pattern, flags));
	};

	// Accepts a `RegExp` instance; returns a copy with the `/g` flag set. The
	// copy has a fresh
	// `lastIndex` (set to zero). If you want to copy a regex without forcing
	// the `global`
	// property, use `XRegExp(regex)`. Do not use `RegExp(regex)` because it
	// will not preserve
	// special properties required for named capture
	XRegExp.copyAsGlobal = function(regex) {
		return clone(regex, "g");
	};

	// Accepts a string; returns the string with regex metacharacters escaped.
	// The returned string
	// can safely be used at any point within a regex to match the provided
	// literal string. Escaped
	// characters are [ ] { } ( ) * + ? - . , \ ^ $ | # and whitespace
	XRegExp.escape = function(str) {
		return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
	};

	// Accepts a string to search, regex to search with, position to start the
	// search within the
	// string (default: 0), and an optional Boolean indicating whether matches
	// must start at-or-
	// after the position or at the specified position only. This function
	// ignores the `lastIndex`
	// of the provided regex in its own handling, but updates the property for
	// compatibility
	XRegExp.execAt = function(str, regex, pos, anchored) {
		var r2 = clone(regex, "g" + ((anchored && hasNativeY) ? "y" : "")), match;
		r2.lastIndex = pos = pos || 0;
		match = r2.exec(str); // Run the altered `exec` (required for
								// `lastIndex` fix, etc.)
		if (anchored && match && match.index !== pos)
			match = null;
		if (regex.global)
			regex.lastIndex = match ? r2.lastIndex : 0;
		return match;
	};

	// Breaks the unrestorable link to XRegExp's private list of tokens, thereby
	// preventing
	// syntax and flag changes. Should be run after XRegExp and any plugins are
	// loaded
	XRegExp.freezeTokens = function() {
		XRegExp.addToken = function() {
			throw Error("can't run addToken after freezeTokens");
		};
	};

	// Accepts any value; returns a Boolean indicating whether the argument is a
	// `RegExp` object.
	// Note that this is also `true` for regex literals and regexes created by
	// the `XRegExp`
	// constructor. This works correctly for variables created in another frame,
	// when `instanceof`
	// and `constructor` checks would fail to work as intended
	XRegExp.isRegExp = function(o) {
		return Object.prototype.toString.call(o) === "[object RegExp]";
	};

	// Executes `callback` once per match within `str`. Provides a simpler and
	// cleaner way to
	// iterate over regex matches compared to the traditional approaches of
	// subverting
	// `String.prototype.replace` or repeatedly calling `exec` within a `while`
	// loop
	XRegExp.iterate = function(str, regex, callback, context) {
		var r2 = clone(regex, "g"), i = -1, match;
		while (match = r2.exec(str)) { // Run the altered `exec` (required for
										// `lastIndex` fix, etc.)
			if (regex.global)
				regex.lastIndex = r2.lastIndex; // Doing this to follow
												// expectations if `lastIndex`
												// is checked within `callback`
			callback.call(context, match, ++i, str, regex);
			if (r2.lastIndex === match.index)
				r2.lastIndex++;
		}
		if (regex.global)
			regex.lastIndex = 0;
	};

	// Accepts a string and an array of regexes; returns the result of using
	// each successive regex
	// to search within the matches of the previous regex. The array of regexes
	// can also contain
	// objects with `regex` and `backref` properties, in which case the named or
	// numbered back-
	// references specified are passed forward to the next regex or returned.
	// E.g.:
	// var xregexpImgFileNames = XRegExp.matchChain(html, [
	// {regex: /<img\b([^>]+)>/i, backref: 1}, // <img> tag attributes
	// {regex: XRegExp('(?ix) \\s src=" (?<src> [^"]+ )'), backref: "src"}, //
	// src attribute values
	// {regex: XRegExp("^http://xregexp\\.com(/[^#?]+)", "i"), backref: 1}, //
	// xregexp.com paths
	// /[^\/]+$/ // filenames (strip directory paths)
	// ]);
	XRegExp.matchChain = function(str, chain) {
		return function recurseChain(values, level) {
			var item = chain[level].regex ? chain[level] : {
				regex : chain[level]
			}, regex = clone(item.regex, "g"), matches = [], i;
			for (i = 0; i < values.length; i++) {
				XRegExp.iterate(values[i], regex, function(match) {
					matches.push(item.backref ? (match[item.backref] || "")
							: match[0]);
				});
			}
			return ((level === chain.length - 1) || !matches.length) ? matches
					: recurseChain(matches, level + 1);
		}([ str ], 0);
	};

	// ---------------------------------
	// New RegExp prototype methods
	// ---------------------------------

	// Accepts a context object and arguments array; returns the result of
	// calling `exec` with the
	// first value in the arguments array. the context is ignored but is
	// accepted for congruity
	// with `Function.prototype.apply`
	RegExp.prototype.apply = function(context, args) {
		return this.exec(args[0]);
	};

	// Accepts a context object and string; returns the result of calling `exec`
	// with the provided
	// string. the context is ignored but is accepted for congruity with
	// `Function.prototype.call`
	RegExp.prototype.call = function(context, str) {
		return this.exec(str);
	};

	// ---------------------------------
	// Overriden native methods
	// ---------------------------------

	// Adds named capture support (with backreferences returned as
	// `result.name`), and fixes two
	// cross-browser issues per ES3:
	// - Captured values for nonparticipating capturing groups should be
	// returned as `undefined`,
	// rather than the empty string.
	// - `lastIndex` should not be incremented after zero-length matches.
	RegExp.prototype.exec = function(str) {
		var match, name, r2, origLastIndex;
		if (!this.global)
			origLastIndex = this.lastIndex;
		match = nativ.exec.apply(this, arguments);
		if (match) {
			// Fix browsers whose `exec` methods don't consistently return
			// `undefined` for
			// nonparticipating capturing groups
			if (!compliantExecNpcg && match.length > 1
					&& indexOf(match, "") > -1) {
				r2 = RegExp(this.source, nativ.replace.call(
						getNativeFlags(this), "g", ""));
				// Using `str.slice(match.index)` rather than `match[0]` in case
				// lookahead allowed
				// matching due to characters outside the match
				nativ.replace.call((str + "").slice(match.index), r2,
						function() {
							for ( var i = 1; i < arguments.length - 2; i++) {
								if (arguments[i] === undefined)
									match[i] = undefined;
							}
						});
			}
			// Attach named capture properties
			if (this._xregexp && this._xregexp.captureNames) {
				for ( var i = 1; i < match.length; i++) {
					name = this._xregexp.captureNames[i - 1];
					if (name)
						match[name] = match[i];
				}
			}
			// Fix browsers that increment `lastIndex` after zero-length matches
			if (!compliantLastIndexIncrement && this.global && !match[0].length
					&& (this.lastIndex > match.index))
				this.lastIndex--;
		}
		if (!this.global)
			this.lastIndex = origLastIndex; // Fix IE, Opera bug (last tested IE
											// 9.0.5, Opera 11.61 on Windows)
		return match;
	};

	// Fix browser bugs in native method
	RegExp.prototype.test = function(str) {
		// Use the native `exec` to skip some processing overhead, even though
		// the altered
		// `exec` would take care of the `lastIndex` fixes
		var match, origLastIndex;
		if (!this.global)
			origLastIndex = this.lastIndex;
		match = nativ.exec.call(this, str);
		// Fix browsers that increment `lastIndex` after zero-length matches
		if (match && !compliantLastIndexIncrement && this.global
				&& !match[0].length && (this.lastIndex > match.index))
			this.lastIndex--;
		if (!this.global)
			this.lastIndex = origLastIndex; // Fix IE, Opera bug (last tested IE
											// 9.0.5, Opera 11.61 on Windows)
		return !!match;
	};

	// Adds named capture support and fixes browser bugs in native method
	String.prototype.match = function(regex) {
		if (!XRegExp.isRegExp(regex))
			regex = RegExp(regex); // Native `RegExp`
		if (regex.global) {
			var result = nativ.match.apply(this, arguments);
			regex.lastIndex = 0; // Fix IE bug
			return result;
		}
		return regex.exec(this); // Run the altered `exec`
	};

	// Adds support for `${n}` tokens for named and numbered backreferences in
	// replacement text,
	// and provides named backreferences to replacement functions as
	// `arguments[0].name`. Also
	// fixes cross-browser differences in replacement text syntax when
	// performing a replacement
	// using a nonregex search value, and the value of replacement regexes'
	// `lastIndex` property
	// during replacement iterations. Note that this doesn't support
	// SpiderMonkey's proprietary
	// third (`flags`) parameter
	String.prototype.replace = function(search, replacement) {
		var isRegex = XRegExp.isRegExp(search), captureNames, result, str, origLastIndex;

		// There are too many combinations of search/replacement types/values
		// and browser bugs that
		// preclude passing to native `replace`, so don't try
		// if (...)
		// return nativ.replace.apply(this, arguments);

		if (isRegex) {
			if (search._xregexp)
				captureNames = search._xregexp.captureNames; // Array or
																// `null`
			if (!search.global)
				origLastIndex = search.lastIndex;
		} else {
			search = search + ""; // Type conversion
		}

		if (Object.prototype.toString.call(replacement) === "[object Function]") {
			result = nativ.replace.call(this + "", search, function() {
				if (captureNames) {
					// Change the `arguments[0]` string primitive to a String
					// object which can store properties
					arguments[0] = new String(arguments[0]);
					// Store named backreferences on `arguments[0]`
					for ( var i = 0; i < captureNames.length; i++) {
						if (captureNames[i])
							arguments[0][captureNames[i]] = arguments[i + 1];
					}
				}
				// Update `lastIndex` before calling `replacement` (fix
				// browsers)
				if (isRegex && search.global)
					search.lastIndex = arguments[arguments.length - 2]
							+ arguments[0].length;
				return replacement.apply(null, arguments);
			});
		} else {
			str = this + ""; // Type conversion, so `args[args.length - 1]`
								// will be a string (given nonstring `this`)
			result = nativ.replace.call(str, search, function() {
				var args = arguments; // Keep this function's `arguments`
										// available through closure
				return nativ.replace.call(replacement + "", replacementToken,
						function($0, $1, $2) {
							// Numbered backreference (without delimiters) or
							// special variable
							if ($1) {
								switch ($1) {
								case "$":
									return "$";
								case "&":
									return args[0];
								case "`":
									return args[args.length - 1].slice(0,
											args[args.length - 2]);
								case "'":
									return args[args.length - 1]
											.slice(args[args.length - 2]
													+ args[0].length);
									// Numbered backreference
								default:
									// What does "$10" mean?
									// - Backreference 10, if 10 or more
									// capturing groups exist
									// - Backreference 1 followed by "0", if 1-9
									// capturing groups exist
									// - Otherwise, it's the string "$10"
									// Also note:
									// - Backreferences cannot be more than two
									// digits (enforced by `replacementToken`)
									// - "$01" is equivalent to "$1" if a
									// capturing group exists, otherwise it's
									// the string "$01"
									// - There is no "$0" token ("$&" is the
									// entire match)
									var literalNumbers = "";
									$1 = +$1; // Type conversion; drop leading
												// zero
									if (!$1) // `$1` was "0" or "00"
										return $0;
									while ($1 > args.length - 3) {
										literalNumbers = String.prototype.slice
												.call($1, -1)
												+ literalNumbers;
										$1 = Math.floor($1 / 10); // Drop the
																	// last
																	// digit
									}
									return ($1 ? args[$1] || "" : "$")
											+ literalNumbers;
								}
								// Named backreference or delimited numbered
								// backreference
							} else {
								// What does "${n}" mean?
								// - Backreference to numbered capture n. Two
								// differences from "$n":
								// - n can be more than two digits
								// - Backreference 0 is allowed, and is the
								// entire match
								// - Backreference to named capture n, if it
								// exists and is not a number overridden by
								// numbered capture
								// - Otherwise, it's the string "${n}"
								var n = +$2; // Type conversion; drop leading
												// zeros
								if (n <= args.length - 3)
									return args[n];
								n = captureNames ? indexOf(captureNames, $2)
										: -1;
								return n > -1 ? args[n + 1] : $0;
							}
						});
			});
		}

		if (isRegex) {
			if (search.global)
				search.lastIndex = 0; // Fix IE, Safari bug (last tested IE
										// 9.0.5, Safari 5.1.2 on Windows)
			else
				search.lastIndex = origLastIndex; // Fix IE, Opera bug (last
													// tested IE 9.0.5, Opera
													// 11.61 on Windows)
		}

		return result;
	};

	// A consistent cross-browser, ES3 compliant `split`
	String.prototype.split = function(s /* separator */, limit) {
		// If separator `s` is not a regex, use the native `split`
		if (!XRegExp.isRegExp(s))
			return nativ.split.apply(this, arguments);

		var str = this + "", // Type conversion
		output = [], lastLastIndex = 0, match, lastLength;

		// Behavior for `limit`: if it's...
		// - `undefined`: No limit
		// - `NaN` or zero: Return an empty array
		// - A positive number: Use `Math.floor(limit)`
		// - A negative number: No limit
		// - Other: Type-convert, then use the above rules
		if (limit === undefined || +limit < 0) {
			limit = Infinity;
		} else {
			limit = Math.floor(+limit);
			if (!limit)
				return [];
		}

		// This is required if not `s.global`, and it avoids needing to set
		// `s.lastIndex` to zero
		// and restore it to its original value when we're done using the regex
		s = XRegExp.copyAsGlobal(s);

		while (match = s.exec(str)) { // Run the altered `exec` (required for
										// `lastIndex` fix, etc.)
			if (s.lastIndex > lastLastIndex) {
				output.push(str.slice(lastLastIndex, match.index));

				if (match.length > 1 && match.index < str.length)
					Array.prototype.push.apply(output, match.slice(1));

				lastLength = match[0].length;
				lastLastIndex = s.lastIndex;

				if (output.length >= limit)
					break;
			}

			if (s.lastIndex === match.index)
				s.lastIndex++;
		}

		if (lastLastIndex === str.length) {
			if (!nativ.test.call(s, "") || lastLength)
				output.push("");
		} else {
			output.push(str.slice(lastLastIndex));
		}

		return output.length > limit ? output.slice(0, limit) : output;
	};

	// ---------------------------------
	// Private helper functions
	// ---------------------------------

	// Supporting function for `XRegExp`, `XRegExp.copyAsGlobal`, etc. Returns a
	// copy of a `RegExp`
	// instance with a fresh `lastIndex` (set to zero), preserving properties
	// required for named
	// capture. Also allows adding new flags in the process of copying the regex
	function clone(regex, additionalFlags) {
		if (!XRegExp.isRegExp(regex))
			throw TypeError("type RegExp expected");
		var x = regex._xregexp;
		regex = XRegExp(regex.source, getNativeFlags(regex)
				+ (additionalFlags || ""));
		if (x) {
			regex._xregexp = {
				source : x.source,
				captureNames : x.captureNames ? x.captureNames.slice(0) : null
			};
		}
		return regex;
	}

	function getNativeFlags(regex) {
		return (regex.global ? "g" : "") + (regex.ignoreCase ? "i" : "")
				+ (regex.multiline ? "m" : "") + (regex.extended ? "x" : "") + // Proposed
																				// for
																				// ES4;
																				// included
																				// in
																				// AS3
				(regex.sticky ? "y" : "");
	}

	function runTokens(pattern, index, scope, context) {
		var i = tokens.length, result, match, t;
		// Protect against constructing XRegExps within token handler and
		// trigger functions
		isInsideConstructor = true;
		// Must reset `isInsideConstructor`, even if a `trigger` or `handler`
		// throws
		try {
			while (i--) { // Run in reverse order
				t = tokens[i];
				if ((scope & t.scope)
						&& (!t.trigger || t.trigger.call(context))) {
					t.pattern.lastIndex = index;
					match = t.pattern.exec(pattern); // Running the altered
														// `exec` here allows
														// use of named
														// backreferences, etc.
					if (match && match.index === index) {
						result = {
							output : t.handler.call(context, match, scope),
							match : match
						};
						break;
					}
				}
			}
		} catch (err) {
			throw err;
		} finally {
			isInsideConstructor = false;
		}
		return result;
	}

	function indexOf(array, item, from) {
		if (Array.prototype.indexOf) // Use the native array method if
										// available
			return array.indexOf(item, from);
		for ( var i = from || 0; i < array.length; i++) {
			if (array[i] === item)
				return i;
		}
		return -1;
	}

	// ---------------------------------
	// Built-in tokens
	// ---------------------------------

	// Augment XRegExp's regular expression syntax and flags. Note that when
	// adding tokens, the
	// third (`scope`) argument defaults to `XRegExp.OUTSIDE_CLASS`

	// Comment pattern: (?# )
	XRegExp.addToken(/\(\?#[^)]*\)/, function(match) {
		// Keep tokens separated unless the following token is a quantifier
		return nativ.test.call(quantifier, match.input.slice(match.index
				+ match[0].length)) ? "" : "(?:)";
	});

	// Capturing group (match the opening parenthesis only).
	// Required for support of named capturing groups
	XRegExp.addToken(/\((?!\?)/, function() {
		this.captureNames.push(null);
		return "(";
	});

	// Named capturing group (match the opening delimiter only): (?<name>
	XRegExp.addToken(/\(\?<([$\w]+)>/, function(match) {
		this.captureNames.push(match[1]);
		this.hasNamedCapture = true;
		return "(";
	});

	// Named backreference: \k<name>
	XRegExp.addToken(/\\k<([\w$]+)>/,
			function(match) {
				var index = indexOf(this.captureNames, match[1]);
				// Keep backreferences separate from subsequent literal numbers.
				// Preserve back-
				// references to named groups that are undefined at this point
				// as literal strings
				return index > -1 ? "\\"
						+ (index + 1)
						+ (isNaN(match.input.charAt(match.index
								+ match[0].length)) ? "" : "(?:)") : match[0];
			});

	// Empty character class: [] or [^]
	XRegExp.addToken(/\[\^?]/, function(match) {
		// For cross-browser compatibility with ES3, convert [] to \b\B and [^]
		// to [\s\S].
		// (?!) should work like \b\B, but is unreliable in Firefox
		return match[0] === "[]" ? "\\b\\B" : "[\\s\\S]";
	});

	// Mode modifier at the start of the pattern only, with any combination of
	// flags imsx: (?imsx)
	// Does not support x(?i), (?-i), (?i-m), (?i: ), (?i)(?m), etc.
	XRegExp.addToken(/^\(\?([imsx]+)\)/, function(match) {
		this.setFlag(match[1]);
		return "";
	});

	// Whitespace and comments, in free-spacing (aka extended) mode only
	XRegExp.addToken(/(?:\s+|#.*)+/, function(match) {
		// Keep tokens separated unless the following token is a quantifier
		return nativ.test.call(quantifier, match.input.slice(match.index
				+ match[0].length)) ? "" : "(?:)";
	}, XRegExp.OUTSIDE_CLASS, function() {
		return this.hasFlag("x");
	});

	// Dot, in dotall (aka singleline) mode only
	XRegExp.addToken(/\./, function() {
		return "[\\s\\S]";
	}, XRegExp.OUTSIDE_CLASS, function() {
		return this.hasFlag("s");
	});

	// ---------------------------------
	// Backward compatibility
	// ---------------------------------

	// Uncomment the following block for compatibility with XRegExp 1.0-1.2:
	/*
	 * XRegExp.matchWithinChain = XRegExp.matchChain; RegExp.prototype.addFlags =
	 * function (s) {return clone(this, s);}; RegExp.prototype.execAll =
	 * function (s) {var r = []; XRegExp.iterate(s, this, function (m)
	 * {r.push(m);}); return r;}; RegExp.prototype.forEachExec = function (s, f,
	 * c) {return XRegExp.iterate(s, this, f, c);}; RegExp.prototype.validate =
	 * function (s) {var r = RegExp("^(?:" + this.source + ")$(?!\\s)",
	 * getNativeFlags(this)); if (this.global) this.lastIndex = 0; return
	 * s.search(r) === 0;};
	 */

})();
// ==========================
// shCore.js
// ==========================
//
// Begin anonymous function. This is used to contain local scope variables
// without polutting global scope.
//
if (typeof (SyntaxHighlighter) == 'undefined')
	var SyntaxHighlighter = function() {

		// CommonJS
		if (typeof (require) != 'undefined' && typeof (XRegExp) == 'undefined') {
			XRegExp = require('XRegExp').XRegExp;
		}

		// Shortcut object which will be assigned to the SyntaxHighlighter
		// variable.
		// This is a shorthand for local reference in order to avoid long
		// namespace
		// references to SyntaxHighlighter.whatever...
		var sh = {
			defaults : {
				/**
				 * Additional CSS class names to be added to highlighter
				 * elements.
				 */
				'class-name' : '',

				/** First line number. */
				'first-line' : 1,

				/**
				 * Pads line numbers. Possible values are:
				 * 
				 * false - don't pad line numbers. true - automaticaly pad
				 * numbers with minimum required number of leading zeroes. [int] -
				 * length up to which pad line numbers.
				 */
				'pad-line-numbers' : false,

				/** Lines to highlight. */
				'highlight' : null,

				/** Title to be displayed above the code block. */
				'title' : null,

				/** Enables or disables smart tabs. */
				'smart-tabs' : true,

				/** Gets or sets tab size. */
				'tab-size' : 4,

				/** Enables or disables gutter. */
				'gutter' : true,

				/** Enables or disables toolbar. */
				'toolbar' : true,

				/** Enables quick code copy and paste from double click. */
				'quick-code' : true,

				/** Forces code view to be collapsed. */
				'collapse' : false,

				/** Enables or disables automatic links. */
				'auto-links' : true,

				/**
				 * Gets or sets light mode. Equavalent to turning off gutter and
				 * toolbar.
				 */
				'light' : false,

				'unindent' : true,

				'html-script' : false
			},

			config : {
				space : '&nbsp;',

				/** Enables use of <SCRIPT type="syntaxhighlighter" /> tags. */
				useScriptTags : true,

				/** Blogger mode flag. */
				bloggerMode : false,

				stripBrs : false,

				/**
				 * Name of the tag that SyntaxHighlighter will automatically
				 * look for.
				 */
				tagName : 'pre',

				strings : {
					expandSource : 'expand source',
					help : '?',
					alert : 'SyntaxHighlighter\n\n',
					noBrush : 'Can\'t find brush for: ',
					brushNotHtmlScript : 'Brush wasn\'t configured for html-script option: ',

					// this is populated by the build script
					aboutDialog : '@ABOUT@'
				}
			},

			/** Internal 'global' variables. */
			vars : {
				discoveredBrushes : null,
				highlighters : {}
			},

			/** This object is populated by user included external brush files. */
			brushes : {},

			/** Common regular expressions. */
			regexLib : {
				multiLineCComments : /\/\*[\s\S]*?\*\//gm,
				singleLineCComments : /\/\/.*$/gm,
				singleLinePerlComments : /#.*$/gm,
				doubleQuotedString : /"([^\\"\n]|\\.)*"/g,
				singleQuotedString : /'([^\\'\n]|\\.)*'/g,
				multiLineDoubleQuotedString : new XRegExp(
						'"([^\\\\"]|\\\\.)*"', 'gs'),
				multiLineSingleQuotedString : new XRegExp(
						"'([^\\\\']|\\\\.)*'", 'gs'),
				xmlComments : /(&lt;|<)!--[\s\S]*?--(&gt;|>)/gm,
				url : /\w+:\/\/[\w-.\/?%&=:@;#]*/g,

				/** <?= ?> tags. */
				phpScriptTags : {
					left : /(&lt;|<)\?(?:=|php)?/g,
					right : /\?(&gt;|>)/g,
					'eof' : true
				},

				/** <%= %> tags. */
				aspScriptTags : {
					left : /(&lt;|<)%=?/g,
					right : /%(&gt;|>)/g
				},

				/** <script> tags. */
				scriptScriptTags : {
					left : /(&lt;|<)\s*script.*?(&gt;|>)/gi,
					right : /(&lt;|<)\/\s*script\s*(&gt;|>)/gi
				}
			},

			toolbar : {
				/**
				 * Generates HTML markup for the toolbar.
				 * 
				 * @param {Highlighter}
				 *            highlighter Highlighter instance.
				 * @return {String} Returns HTML markup.
				 */
				getHtml : function(highlighter) {
					var html = '<div class="toolbar">', items = sh.toolbar.items, list = items.list;

					function defaultGetHtml(highlighter, name) {
						return sh.toolbar.getButtonHtml(highlighter, name,
								sh.config.strings[name]);
					}
					;

					for ( var i = 0; i < list.length; i++)
						html += (items[list[i]].getHtml || defaultGetHtml)(
								highlighter, list[i]);

					html += '</div>';

					return html;
				},

				/**
				 * Generates HTML markup for a regular button in the toolbar.
				 * 
				 * @param {Highlighter}
				 *            highlighter Highlighter instance.
				 * @param {String}
				 *            commandName Command name that would be executed.
				 * @param {String}
				 *            label Label text to display.
				 * @return {String} Returns HTML markup.
				 */
				getButtonHtml : function(highlighter, commandName, label) {
					return '<span><a href="#" class="toolbar_item'
							+ ' command_' + commandName + ' ' + commandName
							+ '">' + label + '</a></span>';
				},

				/**
				 * Event handler for a toolbar anchor.
				 */
				handler : function(e) {
					var target = e.target, className = target.className || '';

					function getValue(name) {
						var r = new RegExp(name + '_(\\w+)'), match = r
								.exec(className);

						return match ? match[1] : null;
					}
					;

					var highlighter = getHighlighterById(findParentElement(
							target, '.syntaxhighlighter').id), commandName = getValue('command');

					// execute the toolbar command
					if (highlighter && commandName)
						sh.toolbar.items[commandName].execute(highlighter);

					// disable default A click behaviour
					e.preventDefault();
				},

				/** Collection of toolbar items. */
				items : {
					// Ordered lis of items in the toolbar. Can't expect `for
					// (var n in items)` to be consistent.
					list : [ 'expandSource', 'help' ],

					expandSource : {
						getHtml : function(highlighter) {
							if (highlighter.getParam('collapse') != true)
								return '';

							var title = highlighter.getParam('title');
							return sh.toolbar.getButtonHtml(highlighter,
									'expandSource', title ? title
											: sh.config.strings.expandSource);
						},

						execute : function(highlighter) {
							var div = getHighlighterDivById(highlighter.id);
							removeClass(div, 'collapsed');
						}
					},

					/** Command to display the about dialog window. */
					help : {
						execute : function(highlighter) {
							var wnd = popup('', '_blank', 500, 250,
									'scrollbars=0'), doc = wnd.document;

							doc.write(sh.config.strings.aboutDialog);
							doc.close();
							wnd.focus();
						}
					}
				}
			},

			/**
			 * Finds all elements on the page which should be processes by
			 * SyntaxHighlighter.
			 * 
			 * @param {Object}
			 *            globalParams Optional parameters which override
			 *            element's parameters. Only used if element is
			 *            specified.
			 * 
			 * @param {Object}
			 *            element Optional element to highlight. If none is
			 *            provided, all elements in the current document are
			 *            returned which qualify.
			 * 
			 * @return {Array} Returns list of
			 *         <code>{ target: DOMElement, params: Object }</code>
			 *         objects.
			 */
			findElements : function(globalParams, element) {
				var elements = element ? [ element ] : toArray(document
						.getElementsByTagName(sh.config.tagName)), conf = sh.config, result = [];

				// support for <SCRIPT TYPE="syntaxhighlighter" /> feature
				if (conf.useScriptTags)
					elements = elements
							.concat(getSyntaxHighlighterScriptTags());

				if (elements.length === 0)
					return result;

				for ( var i = 0; i < elements.length; i++) {
					var item = {
						target : elements[i],
						// local params take precedence over globals
						params : merge(globalParams,
								parseParams(elements[i].className))
					};

					if (item.params['brush'] == null)
						continue;

					result.push(item);
				}

				return result;
			},

			/**
			 * Shorthand to highlight all elements on the page that are marked
			 * as SyntaxHighlighter source code.
			 * 
			 * @param {Object}
			 *            globalParams Optional parameters which override
			 *            element's parameters. Only used if element is
			 *            specified.
			 * 
			 * @param {Object}
			 *            element Optional element to highlight. If none is
			 *            provided, all elements in the current document are
			 *            highlighted.
			 */
			highlight : function(globalParams, element) {
				var elements = this.findElements(globalParams, element), propertyName = 'innerHTML', highlighter = null, conf = sh.config;

				if (elements.length === 0)
					return;

				for ( var i = 0; i < elements.length; i++) {
					var element = elements[i], target = element.target, params = element.params, brushName = params.brush, code;

					if (brushName == null)
						continue;

					// Instantiate a brush
					if (params['html-script'] == 'true'
							|| sh.defaults['html-script'] == true) {
						highlighter = new sh.HtmlScript(brushName);
						brushName = 'htmlscript';
					} else {
						var brush = findBrush(brushName);

						if (brush)
							highlighter = new brush();
						else
							continue;
					}

					code = target[propertyName];

					// remove CDATA from <SCRIPT/> tags if it's present
					if (conf.useScriptTags)
						code = stripCData(code);

					// Inject title if the attribute is present
					if ((target.title || '') != '')
						params.title = target.title;

					params['brush'] = brushName;
					highlighter.init(params);
					element = highlighter.getDiv(code);

					// carry over ID
					if ((target.id || '') != '')
						element.id = target.id;

					target.parentNode.replaceChild(element, target);
				}
			},

			/**
			 * Main entry point for the SyntaxHighlighter.
			 * 
			 * @param {Object}
			 *            params Optional params to apply to all highlighted
			 *            elements.
			 */
			all : function(params) {
				attachEvent(window, 'load', function() {
					sh.highlight(params);
				});
			}
		}; // end of sh

		/**
		 * Checks if target DOM elements has specified CSS class.
		 * 
		 * @param {DOMElement}
		 *            target Target DOM element to check.
		 * @param {String}
		 *            className Name of the CSS class to check for.
		 * @return {Boolean} Returns true if class name is present, false
		 *         otherwise.
		 */
		function hasClass(target, className) {
			return target.className.indexOf(className) != -1;
		}
		;

		/**
		 * Adds CSS class name to the target DOM element.
		 * 
		 * @param {DOMElement}
		 *            target Target DOM element.
		 * @param {String}
		 *            className New CSS class to add.
		 */
		function addClass(target, className) {
			if (!hasClass(target, className))
				target.className += ' ' + className;
		}
		;

		/**
		 * Removes CSS class name from the target DOM element.
		 * 
		 * @param {DOMElement}
		 *            target Target DOM element.
		 * @param {String}
		 *            className CSS class to remove.
		 */
		function removeClass(target, className) {
			target.className = target.className.replace(className, '');
		}
		;

		/**
		 * Converts the source to array object. Mostly used for function
		 * arguments and lists returned by getElementsByTagName() which aren't
		 * Array objects.
		 * 
		 * @param {List}
		 *            source Source list.
		 * @return {Array} Returns array.
		 */
		function toArray(source) {
			var result = [];

			for ( var i = 0; i < source.length; i++)
				result.push(source[i]);

			return result;
		}
		;

		/**
		 * Splits block of text into lines.
		 * 
		 * @param {String}
		 *            block Block of text.
		 * @return {Array} Returns array of lines.
		 */
		function splitLines(block) {
			return block.split(/\r?\n/);
		}

		/**
		 * Generates HTML ID for the highlighter.
		 * 
		 * @param {String}
		 *            highlighterId Highlighter ID.
		 * @return {String} Returns HTML ID.
		 */
		function getHighlighterId(id) {
			var prefix = 'highlighter_';
			return id.indexOf(prefix) == 0 ? id : prefix + id;
		}
		;

		/**
		 * Finds Highlighter instance by ID.
		 * 
		 * @param {String}
		 *            highlighterId Highlighter ID.
		 * @return {Highlighter} Returns instance of the highlighter.
		 */
		function getHighlighterById(id) {
			return sh.vars.highlighters[getHighlighterId(id)];
		}
		;

		/**
		 * Finds highlighter's DIV container.
		 * 
		 * @param {String}
		 *            highlighterId Highlighter ID.
		 * @return {Element} Returns highlighter's DIV element.
		 */
		function getHighlighterDivById(id) {
			return document.getElementById(getHighlighterId(id));
		}
		;

		/**
		 * Stores highlighter so that getHighlighterById() can do its thing.
		 * Each highlighter must call this method to preserve itself.
		 * 
		 * @param {Highilghter}
		 *            highlighter Highlighter instance.
		 */
		function storeHighlighter(highlighter) {
			sh.vars.highlighters[getHighlighterId(highlighter.id)] = highlighter;
		}
		;

		/**
		 * Looks for a child or parent node which has specified classname.
		 * Equivalent to jQuery's $(container).find(".className")
		 * 
		 * @param {Element}
		 *            target Target element.
		 * @param {String}
		 *            search Class name or node name to look for.
		 * @param {Boolean}
		 *            reverse If set to true, will go up the node tree instead
		 *            of down.
		 * @return {Element} Returns found child or parent element on null.
		 */
		function findElement(target, search, reverse /* optional */) {
			if (target == null)
				return null;

			var nodes = reverse != true ? target.childNodes
					: [ target.parentNode ], propertyToFind = {
				'#' : 'id',
				'.' : 'className'
			}[search.substr(0, 1)] || 'nodeName', expectedValue, found;

			expectedValue = propertyToFind != 'nodeName' ? search.substr(1)
					: search.toUpperCase();

			// main return of the found node
			if ((target[propertyToFind] || '').indexOf(expectedValue) != -1)
				return target;

			for ( var i = 0; nodes && i < nodes.length && found == null; i++)
				found = findElement(nodes[i], search, reverse);

			return found;
		}
		;

		/**
		 * Looks for a parent node which has specified classname. This is an
		 * alias to <code>findElement(container, className, true)</code>.
		 * 
		 * @param {Element}
		 *            target Target element.
		 * @param {String}
		 *            className Class name to look for.
		 * @return {Element} Returns found parent element on null.
		 */
		function findParentElement(target, className) {
			return findElement(target, className, true);
		}
		;

		/**
		 * Finds an index of element in the array.
		 * 
		 * @ignore
		 * @param {Object}
		 *            searchElement
		 * @param {Number}
		 *            fromIndex
		 * @return {Number} Returns index of element if found; -1 otherwise.
		 */
		function indexOf(array, searchElement, fromIndex) {
			fromIndex = Math.max(fromIndex || 0, 0);

			for ( var i = fromIndex; i < array.length; i++)
				if (array[i] == searchElement)
					return i;

			return -1;
		}
		;

		/**
		 * Generates a unique element ID.
		 */
		function guid(prefix) {
			return (prefix || '')
					+ Math.round(Math.random() * 1000000).toString();
		}
		;

		/**
		 * Merges two objects. Values from obj2 override values in obj1.
		 * Function is NOT recursive and works only for one dimensional objects.
		 * 
		 * @param {Object}
		 *            obj1 First object.
		 * @param {Object}
		 *            obj2 Second object.
		 * @return {Object} Returns combination of both objects.
		 */
		function merge(obj1, obj2) {
			var result = {}, name;

			for (name in obj1)
				result[name] = obj1[name];

			for (name in obj2)
				result[name] = obj2[name];

			return result;
		}
		;

		/**
		 * Attempts to convert string to boolean.
		 * 
		 * @param {String}
		 *            value Input string.
		 * @return {Boolean} Returns true if input was "true", false if input
		 *         was "false" and value otherwise.
		 */
		function toBoolean(value) {
			var result = {
				"true" : true,
				"false" : false
			}[value];
			return result == null ? value : result;
		}
		;

		/**
		 * Opens up a centered popup window.
		 * 
		 * @param {String}
		 *            url URL to open in the window.
		 * @param {String}
		 *            name Popup name.
		 * @param {int}
		 *            width Popup width.
		 * @param {int}
		 *            height Popup height.
		 * @param {String}
		 *            options window.open() options.
		 * @return {Window} Returns window instance.
		 */
		function popup(url, name, width, height, options) {
			var x = (screen.width - width) / 2, y = (screen.height - height) / 2;

			options += ', left=' + x + ', top=' + y + ', width=' + width
					+ ', height=' + height;
			options = options.replace(/^,/, '');

			var win = window.open(url, name, options);
			win.focus();
			return win;
		}
		;

		/**
		 * Adds event handler to the target object.
		 * 
		 * @param {Object}
		 *            obj Target object.
		 * @param {String}
		 *            type Name of the event.
		 * @param {Function}
		 *            func Handling function.
		 */
		function attachEvent(obj, type, func, scope) {
			function handler(e) {
				e = e || window.event;

				if (!e.target) {
					e.target = e.srcElement;
					e.preventDefault = function() {
						this.returnValue = false;
					};
				}

				func.call(scope || window, e);
			}
			;

			if (obj.attachEvent) {
				obj.attachEvent('on' + type, handler);
			} else {
				obj.addEventListener(type, handler, false);
			}
		}
		;

		/**
		 * Displays an alert.
		 * 
		 * @param {String}
		 *            str String to display.
		 */
		function alert(str) {
			window.alert(sh.config.strings.alert + str);
		}
		;

		/**
		 * Finds a brush by its alias.
		 * 
		 * @param {String}
		 *            alias Brush alias.
		 * @param {Boolean}
		 *            showAlert Suppresses the alert if false.
		 * @return {Brush} Returns bursh constructor if found, null otherwise.
		 */
		function findBrush(alias, showAlert) {
			var brushes = sh.vars.discoveredBrushes, result = null;

			if (brushes == null) {
				brushes = {};

				// Find all brushes
				for ( var brush in sh.brushes) {
					var info = sh.brushes[brush], aliases = info.aliases;

					if (aliases == null)
						continue;

					// keep the brush name
					info.brushName = brush.toLowerCase();

					for ( var i = 0; i < aliases.length; i++)
						brushes[aliases[i]] = brush;
				}

				sh.vars.discoveredBrushes = brushes;
			}

			result = sh.brushes[brushes[alias]];

			if (result == null && showAlert)
				alert(sh.config.strings.noBrush + alias);

			return result;
		}
		;

		/**
		 * Executes a callback on each line and replaces each line with result
		 * from the callback.
		 * 
		 * @param {Object}
		 *            str Input string.
		 * @param {Object}
		 *            callback Callback function taking one string argument and
		 *            returning a string.
		 */
		function eachLine(str, callback) {
			var lines = splitLines(str);

			for ( var i = 0; i < lines.length; i++)
				lines[i] = callback(lines[i], i);

			// include \r to enable copy-paste on windows (ie8) without getting
			// everything on one line
			return lines.join('\r\n');
		}
		;

		/**
		 * This is a special trim which only removes first and last empty lines
		 * and doesn't affect valid leading space on the first line.
		 * 
		 * @param {String}
		 *            str Input string
		 * @return {String} Returns string without empty first and last lines.
		 */
		function trimFirstAndLastLines(str) {
			return str.replace(/^[ ]*[\n]+|[\n]*[ ]*$/g, '');
		}
		;

		/**
		 * Parses key/value pairs into hash object.
		 * 
		 * Understands the following formats: - name: word; - name: [word,
		 * word]; - name: "string"; - name: 'string';
		 * 
		 * For example: name1: value; name2: [value, value]; name3: 'value'
		 * 
		 * @param {String}
		 *            str Input string.
		 * @return {Object} Returns deserialized object.
		 */
		function parseParams(str) {
			var match, result = {}, arrayRegex = new XRegExp(
					"^\\[(?<values>(.*?))\\]$"), regex = new XRegExp(
					"(?<name>[\\w-]+)" + "\\s*:\\s*" + "(?<value>"
							+ "[\\w-%#]+|" + // word
							"\\[.*?\\]|" + // [] array
							'".*?"|' + // "" string
							"'.*?'" + // '' string
							")\\s*;?", "g");

			while ((match = regex.exec(str)) != null) {
				var value = match.value.replace(/^['"]|['"]$/g, '') // strip
																	// quotes
																	// from end
																	// of
																	// strings
				;

				// try to parse array value
				if (value != null && arrayRegex.test(value)) {
					var m = arrayRegex.exec(value);
					value = m.values.length > 0 ? m.values.split(/\s*,\s*/)
							: [];
				}

				result[match.name] = value;
			}

			return result;
		}
		;

		/**
		 * Wraps each line of the string into <code/>
		 * tag with given style applied to it.
		 * 
		 * @param {String} str   Input string.
		 * @param {String} css   Style name to apply to the string.
		 * @return {String}      Returns input string with each line surrounded by <span/> tag.
		 */
		function wrapLinesWithCode(str, css) {
			if (str == null || str.length == 0 || str == '\n')
				return str;

			str = str.replace(/</g, '&lt;');

			// Replace two or more sequential spaces with &nbsp; leaving last
			// space untouched.
			str = str.replace(/ {2,}/g, function(m) {
				var spaces = '';

				for ( var i = 0; i < m.length - 1; i++)
					spaces += sh.config.space;

				return spaces + ' ';
			});

			// Split each line and apply <span class="...">...</span> to them so
			// that
			// leading spaces aren't included.
			if (css != null)
				str = eachLine(str, function(line) {
					if (line.length == 0)
						return '';

					var spaces = '';

					line = line.replace(/^(&nbsp;| )+/, function(s) {
						spaces = s;
						return '';
					});

					if (line.length == 0)
						return spaces;

					return spaces + '<code class="' + css + '">' + line
							+ '</code>';
				});

			return str;
		}
		;

		/**
		 * Pads number with zeros until it's length is the same as given length.
		 * 
		 * @param {Number}
		 *            number Number to pad.
		 * @param {Number}
		 *            length Max string length with.
		 * @return {String} Returns a string padded with proper amount of '0'.
		 */
		function padNumber(number, length) {
			var result = number.toString();

			while (result.length < length)
				result = '0' + result;

			return result;
		}
		;

		/**
		 * Replaces tabs with spaces.
		 * 
		 * @param {String}
		 *            code Source code.
		 * @param {Number}
		 *            tabSize Size of the tab.
		 * @return {String} Returns code with all tabs replaces by spaces.
		 */
		function processTabs(code, tabSize) {
			var tab = '';

			for ( var i = 0; i < tabSize; i++)
				tab += ' ';

			return code.replace(/\t/g, tab);
		}
		;

		/**
		 * Replaces tabs with smart spaces.
		 * 
		 * @param {String}
		 *            code Code to fix the tabs in.
		 * @param {Number}
		 *            tabSize Number of spaces in a column.
		 * @return {String} Returns code with all tabs replaces with roper
		 *         amount of spaces.
		 */
		function processSmartTabs(code, tabSize) {
			var lines = splitLines(code), tab = '\t', spaces = '';

			// Create a string with 1000 spaces to copy spaces from...
			// It's assumed that there would be no indentation longer than that.
			for ( var i = 0; i < 50; i++)
				spaces += '                    '; // 20 spaces * 50

			// This function inserts specified amount of spaces in the string
			// where a tab is while removing that given tab.
			function insertSpaces(line, pos, count) {
				return line.substr(0, pos) + spaces.substr(0, count)
						+ line.substr(pos + 1, line.length) // pos + 1 will get
															// rid of the tab
				;
			}
			;

			// Go through all the lines and do the 'smart tabs' magic.
			code = eachLine(code, function(line) {
				if (line.indexOf(tab) == -1)
					return line;

				var pos = 0;

				while ((pos = line.indexOf(tab)) != -1) {
					// This is pretty much all there is to the 'smart tabs'
					// logic.
					// Based on the position within the line and size of a tab,
					// calculate the amount of spaces we need to insert.
					var spaces = tabSize - pos % tabSize;
					line = insertSpaces(line, pos, spaces);
				}

				return line;
			});

			return code;
		}
		;

		/**
		 * Performs various string fixes based on configuration.
		 */
		function fixInputString(str) {
			var br = /<br\s*\/?>|&lt;br\s*\/?&gt;/gi;

			if (sh.config.bloggerMode == true)
				str = str.replace(br, '\n');

			if (sh.config.stripBrs == true)
				str = str.replace(br, '');

			return str;
		}
		;

		/**
		 * Removes all white space at the begining and end of a string.
		 * 
		 * @param {String}
		 *            str String to trim.
		 * @return {String} Returns string without leading and following white
		 *         space characters.
		 */
		function trim(str) {
			return str.replace(/^\s+|\s+$/g, '');
		}
		;

		/**
		 * Unindents a block of text by the lowest common indent amount.
		 * 
		 * @param {String}
		 *            str Text to unindent.
		 * @return {String} Returns unindented text block.
		 */
		function unindent(str) {
			var lines = splitLines(fixInputString(str)), indents = new Array(), regex = /^\s*/, min = 1000;

			// go through every line and check for common number of indents
			for ( var i = 0; i < lines.length && min > 0; i++) {
				var line = lines[i];

				if (trim(line).length == 0)
					continue;

				var matches = regex.exec(line);

				// In the event that just one line doesn't have leading white
				// space
				// we can't unindent anything, so bail completely.
				if (matches == null)
					return str;

				min = Math.min(matches[0].length, min);
			}

			// trim minimum common number of white space from the begining of
			// every line
			if (min > 0)
				for ( var i = 0; i < lines.length; i++)
					lines[i] = lines[i].substr(min);

			return lines.join('\n');
		}
		;

		/**
		 * Callback method for Array.sort() which sorts matches by index
		 * position and then by length.
		 * 
		 * @param {Match}
		 *            m1 Left object.
		 * @param {Match}
		 *            m2 Right object.
		 * @return {Number} Returns -1, 0 or -1 as a comparison result.
		 */
		function matchesSortCallback(m1, m2) {
			// sort matches by index first
			if (m1.index < m2.index)
				return -1;
			else if (m1.index > m2.index)
				return 1;
			else {
				// if index is the same, sort by length
				if (m1.length < m2.length)
					return -1;
				else if (m1.length > m2.length)
					return 1;
			}

			return 0;
		}
		;

		/**
		 * Executes given regular expression on provided code and returns all
		 * matches that are found.
		 * 
		 * @param {String}
		 *            code Code to execute regular expression on.
		 * @param {Object}
		 *            regex Regular expression item info from
		 *            <code>regexList</code> collection.
		 * @return {Array} Returns a list of Match objects.
		 */
		function getMatches(code, regexInfo) {
			function defaultAdd(match, regexInfo) {
				return match[0];
			}
			;

			var index = 0, match = null, matches = [], func = regexInfo.func ? regexInfo.func
					: defaultAdd;

			while ((match = regexInfo.regex.exec(code)) != null) {
				var resultMatch = func(match, regexInfo);

				if (typeof (resultMatch) == 'string')
					resultMatch = [ new sh.Match(resultMatch, match.index,
							regexInfo.css) ];

				matches = matches.concat(resultMatch);
			}

			return matches;
		}
		;

		/**
		 * Turns all URLs in the code into <a/> tags.
		 * 
		 * @param {String}
		 *            code Input code.
		 * @return {String} Returns code with </a> tags.
		 */
		function processUrls(code) {
			var gt = /(.*)((&gt;|&lt;).*)/;

			return code.replace(sh.regexLib.url, function(m) {
				var suffix = '', match = null;

				// We include &lt; and &gt; in the URL for the common cases like
				// <http://google.com>
				// The problem is that they get transformed into
				// &lt;http://google.com&gt;
				// Where as &gt; easily looks like part of the URL string.

				if (match = gt.exec(m)) {
					m = match[1];
					suffix = match[2];
				}

				return '<a href="' + m + '">' + m + '</a>' + suffix;
			});
		}
		;

		/**
		 * Finds all <SCRIPT TYPE="syntaxhighlighter" /> elementss.
		 * 
		 * @return {Array} Returns array of all found SyntaxHighlighter tags.
		 */
		function getSyntaxHighlighterScriptTags() {
			var tags = document.getElementsByTagName('script'), result = [];

			for ( var i = 0; i < tags.length; i++)
				if (tags[i].type == 'syntaxhighlighter')
					result.push(tags[i]);

			return result;
		}
		;

		/**
		 * Strips <![CDATA[]]> from <SCRIPT /> content because it should be used
		 * there in most cases for XHTML compliance.
		 * 
		 * @param {String}
		 *            original Input code.
		 * @return {String} Returns code without leading <![CDATA[]]> tags.
		 */
		function stripCData(original) {
			var left = '<![CDATA[', right = ']]>',
			// for some reason IE inserts some leading blanks here
			copy = trim(original), changed = false, leftLength = left.length, rightLength = right.length;

			if (copy.indexOf(left) == 0) {
				copy = copy.substring(leftLength);
				changed = true;
			}

			var copyLength = copy.length;

			if (copy.indexOf(right) == copyLength - rightLength) {
				copy = copy.substring(0, copyLength - rightLength);
				changed = true;
			}

			return changed ? copy : original;
		}
		;

		/**
		 * Quick code mouse double click handler.
		 */
		function quickCodeHandler(e) {
			var target = e.target, highlighterDiv = findParentElement(target,
					'.syntaxhighlighter'), container = findParentElement(
					target, '.container'), textarea = document
					.createElement('textarea'), highlighter;

			if (!container || !highlighterDiv
					|| findElement(container, 'textarea'))
				return;

			highlighter = getHighlighterById(highlighterDiv.id);

			// add source class name
			addClass(highlighterDiv, 'source');

			// Have to go over each line and grab it's text, can't just do it on
			// the
			// container because Firefox loses all \n where as Webkit doesn't.
			var lines = container.childNodes, code = [];

			for ( var i = 0; i < lines.length; i++)
				code.push(lines[i].innerText || lines[i].textContent);

			// using \r instead of \r or \r\n makes this work equally well on
			// IE, FF and Webkit
			code = code.join('\r');

			// For Webkit browsers, replace nbsp with a breaking space
			code = code.replace(/\u00a0/g, " ");

			// inject <textarea/> tag
			textarea.appendChild(document.createTextNode(code));
			container.appendChild(textarea);

			// preselect all text
			textarea.focus();
			textarea.select();

			// set up handler for lost focus
			attachEvent(textarea, 'blur', function(e) {
				textarea.parentNode.removeChild(textarea);
				removeClass(highlighterDiv, 'source');
			});
		}
		;

		/**
		 * Match object.
		 */
		sh.Match = function(value, index, css) {
			this.value = value;
			this.index = index;
			this.length = value.length;
			this.css = css;
			this.brushName = null;
		};

		sh.Match.prototype.toString = function() {
			return this.value;
		};

		/**
		 * Simulates HTML code with a scripting language embedded.
		 * 
		 * @param {String}
		 *            scriptBrushName Brush name of the scripting language.
		 */
		sh.HtmlScript = function(scriptBrushName) {
			var brushClass = findBrush(scriptBrushName), scriptBrush, xmlBrush = new sh.brushes.Xml(), bracketsRegex = null, ref = this, methodsToExpose = 'getDiv getHtml init'
					.split(' ');

			if (brushClass == null)
				return;

			scriptBrush = new brushClass();

			for ( var i = 0; i < methodsToExpose.length; i++)
				// make a closure so we don't lose the name after i changes
				(function() {
					var name = methodsToExpose[i];

					ref[name] = function() {
						return xmlBrush[name].apply(xmlBrush, arguments);
					};
				})();

			if (scriptBrush.htmlScript == null) {
				alert(sh.config.strings.brushNotHtmlScript + scriptBrushName);
				return;
			}

			xmlBrush.regexList.push({
				regex : scriptBrush.htmlScript.code,
				func : process
			});

			function offsetMatches(matches, offset) {
				for ( var j = 0; j < matches.length; j++)
					matches[j].index += offset;
			}

			function process(match, info) {
				var code = match.code, matches = [], regexList = scriptBrush.regexList, offset = match.index
						+ match.left.length, htmlScript = scriptBrush.htmlScript, result;

				// add all matches from the code
				for ( var i = 0; i < regexList.length; i++) {
					result = getMatches(code, regexList[i]);
					offsetMatches(result, offset);
					matches = matches.concat(result);
				}

				// add left script bracket
				if (htmlScript.left != null && match.left != null) {
					result = getMatches(match.left, htmlScript.left);
					offsetMatches(result, match.index);
					matches = matches.concat(result);
				}

				// add right script bracket
				if (htmlScript.right != null && match.right != null) {
					result = getMatches(match.right, htmlScript.right);
					offsetMatches(result, match.index
							+ match[0].lastIndexOf(match.right));
					matches = matches.concat(result);
				}

				for ( var j = 0; j < matches.length; j++)
					matches[j].brushName = brushClass.brushName;

				return matches;
			}
		};

		/**
		 * Main Highlither class.
		 * 
		 * @constructor
		 */
		sh.Highlighter = function() {
			// not putting any code in here because of the prototype inheritance
		};

		sh.Highlighter.prototype = {
			/**
			 * Returns value of the parameter passed to the highlighter.
			 * 
			 * @param {String}
			 *            name Name of the parameter.
			 * @param {Object}
			 *            defaultValue Default value.
			 * @return {Object} Returns found value or default value otherwise.
			 */
			getParam : function(name, defaultValue) {
				var result = this.params[name];
				return toBoolean(result == null ? defaultValue : result);
			},

			/**
			 * Shortcut to document.createElement().
			 * 
			 * @param {String}
			 *            name Name of the element to create (DIV, A, etc).
			 * @return {HTMLElement} Returns new HTML element.
			 */
			create : function(name) {
				return document.createElement(name);
			},

			/**
			 * Applies all regular expression to the code and stores all found
			 * matches in the `this.matches` array.
			 * 
			 * @param {Array}
			 *            regexList List of regular expressions.
			 * @param {String}
			 *            code Source code.
			 * @return {Array} Returns list of matches.
			 */
			findMatches : function(regexList, code) {
				var result = [];

				if (regexList != null)
					for ( var i = 0; i < regexList.length; i++)
						// BUG: length returns len+1 for array if methods added
						// to prototype chain (oising@gmail.com)
						if (typeof (regexList[i]) == "object")
							result = result.concat(getMatches(code,
									regexList[i]));

				// sort and remove nested the matches
				return this.removeNestedMatches(result
						.sort(matchesSortCallback));
			},

			/**
			 * Checks to see if any of the matches are inside of other matches.
			 * This process would get rid of highligted strings inside comments,
			 * keywords inside strings and so on.
			 */
			removeNestedMatches : function(matches) {
				// Optimized by Jose Prado (http://joseprado.com)
				for ( var i = 0; i < matches.length; i++) {
					if (matches[i] === null)
						continue;

					var itemI = matches[i], itemIEndPos = itemI.index
							+ itemI.length;

					for ( var j = i + 1; j < matches.length
							&& matches[i] !== null; j++) {
						var itemJ = matches[j];

						if (itemJ === null)
							continue;
						else if (itemJ.index > itemIEndPos)
							break;
						else if (itemJ.index == itemI.index
								&& itemJ.length > itemI.length)
							matches[i] = null;
						else if (itemJ.index >= itemI.index
								&& itemJ.index < itemIEndPos)
							matches[j] = null;
					}
				}

				return matches;
			},

			/**
			 * Creates an array containing integer line numbers starting from
			 * the 'first-line' param.
			 * 
			 * @return {Array} Returns array of integers.
			 */
			figureOutLineNumbers : function(code) {
				var lines = [], firstLine = parseInt(this
						.getParam('first-line'));

				eachLine(code, function(line, index) {
					lines.push(index + firstLine);
				});

				return lines;
			},

			/**
			 * Determines if specified line number is in the highlighted list.
			 */
			isLineHighlighted : function(lineNumber) {
				var list = this.getParam('highlight', []);

				if (typeof (list) != 'object' && list.push == null)
					list = [ list ];

				return indexOf(list, lineNumber.toString()) != -1;
			},

			/**
			 * Generates HTML markup for a single line of code while determining
			 * alternating line style.
			 * 
			 * @param {Integer}
			 *            lineNumber Line number.
			 * @param {String}
			 *            code Line HTML markup.
			 * @return {String} Returns HTML markup.
			 */
			getLineHtml : function(lineIndex, lineNumber, code) {
				var classes = [ 'line', 'number' + lineNumber,
						'index' + lineIndex,
						'alt' + (lineNumber % 2 == 0 ? 1 : 2).toString() ];

				if (this.isLineHighlighted(lineNumber))
					classes.push('highlighted');

				if (lineNumber == 0)
					classes.push('break');

				return '<div class="' + classes.join(' ') + '">' + code
						+ '</div>';
			},

			/**
			 * Generates HTML markup for line number column.
			 * 
			 * @param {String}
			 *            code Complete code HTML markup.
			 * @param {Array}
			 *            lineNumbers Calculated line numbers.
			 * @return {String} Returns HTML markup.
			 */
			getLineNumbersHtml : function(code, lineNumbers) {
				var html = '', count = splitLines(code).length, firstLine = parseInt(this
						.getParam('first-line')), pad = this
						.getParam('pad-line-numbers');

				if (pad == true)
					pad = (firstLine + count - 1).toString().length;
				else if (isNaN(pad) == true)
					pad = 0;

				for ( var i = 0; i < count; i++) {
					var lineNumber = lineNumbers ? lineNumbers[i] : firstLine
							+ i, code = lineNumber == 0 ? sh.config.space
							: padNumber(lineNumber, pad);

					html += this.getLineHtml(i, lineNumber, code);
				}

				return html;
			},

			/**
			 * Splits block of text into individual DIV lines.
			 * 
			 * @param {String}
			 *            code Code to highlight.
			 * @param {Array}
			 *            lineNumbers Calculated line numbers.
			 * @return {String} Returns highlighted code in HTML form.
			 */
			getCodeLinesHtml : function(html, lineNumbers) {
				html = trim(html);

				var lines = splitLines(html), padLength = this
						.getParam('pad-line-numbers'), firstLine = parseInt(this
						.getParam('first-line')), html = '', brushName = this
						.getParam('brush');

				for ( var i = 0; i < lines.length; i++) {
					var line = lines[i], indent = /^(&nbsp;|\s)+/.exec(line), spaces = null, lineNumber = lineNumbers ? lineNumbers[i]
							: firstLine + i;
					;

					if (indent != null) {
						spaces = indent[0].toString();
						line = line.substr(spaces.length);
						spaces = spaces.replace(' ', sh.config.space);
					}

					line = trim(line);

					if (line.length == 0)
						line = sh.config.space;

					html += this.getLineHtml(i, lineNumber,
							(spaces != null ? '<code class="' + brushName
									+ ' spaces">' + spaces + '</code>' : '')
									+ line);
				}

				return html;
			},

			/**
			 * Returns HTML for the table title or empty string if title is
			 * null.
			 */
			getTitleHtml : function(title) {
				return title ? '<caption>' + title + '</caption>' : '';
			},

			/**
			 * Finds all matches in the source code.
			 * 
			 * @param {String}
			 *            code Source code to process matches in.
			 * @param {Array}
			 *            matches Discovered regex matches.
			 * @return {String} Returns formatted HTML with processed mathes.
			 */
			getMatchesHtml : function(code, matches) {
				var pos = 0, result = '', brushName = this
						.getParam('brush', '');

				function getBrushNameCss(match) {
					var result = match ? (match.brushName || brushName)
							: brushName;
					return result ? result + ' ' : '';
				}
				;

				// Finally, go through the final list of matches and pull the
				// all
				// together adding everything in between that isn't a match.
				for ( var i = 0; i < matches.length; i++) {
					var match = matches[i], matchBrushName;

					if (match === null || match.length === 0)
						continue;

					matchBrushName = getBrushNameCss(match);

					result += wrapLinesWithCode(code.substr(pos, match.index
							- pos), matchBrushName + 'plain')
							+ wrapLinesWithCode(match.value, matchBrushName
									+ match.css);

					pos = match.index + match.length + (match.offset || 0);
				}

				// don't forget to add whatever's remaining in the string
				result += wrapLinesWithCode(code.substr(pos), getBrushNameCss()
						+ 'plain');

				return result;
			},

			/**
			 * Generates HTML markup for the whole syntax highlighter.
			 * 
			 * @param {String}
			 *            code Source code.
			 * @return {String} Returns HTML markup.
			 */
			getHtml : function(code) {
				var html = '', classes = [ 'syntaxhighlighter' ], tabSize, matches, lineNumbers;

				// process light mode
				if (this.getParam('light') == true)
					this.params.toolbar = this.params.gutter = false;

				className = 'syntaxhighlighter';

				if (this.getParam('collapse') == true)
					classes.push('collapsed');

				if ((gutter = this.getParam('gutter')) == false)
					classes.push('nogutter');

				// add custom user style name
				classes.push(this.getParam('class-name'));

				// add brush alias to the class name for custom CSS
				classes.push(this.getParam('brush'));

				code = trimFirstAndLastLines(code).replace(/\r/g, ' ') // IE
																		// lets
																		// these
																		// buggers
																		// through
				;

				tabSize = this.getParam('tab-size');

				// replace tabs with spaces
				code = this.getParam('smart-tabs') == true ? processSmartTabs(
						code, tabSize) : processTabs(code, tabSize);

				// unindent code by the common indentation
				if (this.getParam('unindent'))
					code = unindent(code);

				if (gutter)
					lineNumbers = this.figureOutLineNumbers(code);

				// find matches in the code using brushes regex list
				matches = this.findMatches(this.regexList, code);
				// processes found matches into the html
				html = this.getMatchesHtml(code, matches);
				// finally, split all lines so that they wrap well
				html = this.getCodeLinesHtml(html, lineNumbers);

				// finally, process the links
				if (this.getParam('auto-links'))
					html = processUrls(html);

				if (typeof (navigator) != 'undefined' && navigator.userAgent
						&& navigator.userAgent.match(/MSIE/))
					classes.push('ie');

				html = '<div id="'
						+ getHighlighterId(this.id)
						+ '" class="'
						+ classes.join(' ')
						+ '">'
						+ (this.getParam('toolbar') ? sh.toolbar.getHtml(this)
								: '')
						+ '<table border="0" cellpadding="0" cellspacing="0">'
						+ this.getTitleHtml(this.getParam('title'))
						+ '<tbody>'
						+ '<tr>'
						+ (gutter ? '<td class="gutter">'
								+ this.getLineNumbersHtml(code) + '</td>' : '')
						+ '<td class="code">' + '<div class="container">'
						+ html + '</div>' + '</td>' + '</tr>' + '</tbody>'
						+ '</table>' + '</div>';

				return html;
			},

			/**
			 * Highlights the code and returns complete HTML.
			 * 
			 * @param {String}
			 *            code Code to highlight.
			 * @return {Element} Returns container DIV element with all markup.
			 */
			getDiv : function(code) {
				if (code === null)
					code = '';

				this.code = code;

				var div = this.create('div');

				// create main HTML
				div.innerHTML = this.getHtml(code);

				// set up click handlers
				if (this.getParam('toolbar'))
					attachEvent(findElement(div, '.toolbar'), 'click',
							sh.toolbar.handler);

				if (this.getParam('quick-code'))
					attachEvent(findElement(div, '.code'), 'dblclick',
							quickCodeHandler);

				return div;
			},

			/**
			 * Initializes the highlighter/brush.
			 * 
			 * Constructor isn't used for initialization so that nothing
			 * executes during necessary `new SyntaxHighlighter.Highlighter()`
			 * call when setting up brush inheritence.
			 * 
			 * @param {Hash}
			 *            params Highlighter parameters.
			 */
			init : function(params) {
				this.id = guid();

				// register this instance in the highlighters list
				storeHighlighter(this);

				// local params take precedence over defaults
				this.params = merge(sh.defaults, params || {})

				// process light mode
				if (this.getParam('light') == true)
					this.params.toolbar = this.params.gutter = false;
			},

			/**
			 * Converts space separated list of keywords into a regular
			 * expression string.
			 * 
			 * @param {String}
			 *            str Space separated keywords.
			 * @return {String} Returns regular expression string.
			 */
			getKeywords : function(str) {
				str = str.replace(/^\s+|\s+$/g, '').replace(/\s+/g, '|');

				return '\\b(?:' + str + ')\\b';
			},

			/**
			 * Makes a brush compatible with the `html-script` functionality.
			 * 
			 * @param {Object}
			 *            regexGroup Object containing `left` and `right`
			 *            regular expressions.
			 */
			forHtmlScript : function(regexGroup) {
				var regex = {
					'end' : regexGroup.right.source
				};

				if (regexGroup.eof)
					regex.end = "(?:(?:" + regex.end + ")|$)";

				this.htmlScript = {
					left : {
						regex : regexGroup.left,
						css : 'script'
					},
					right : {
						regex : regexGroup.right,
						css : 'script'
					},
					code : new XRegExp("(?<left>" + regexGroup.left.source
							+ ")" + "(?<code>.*?)" + "(?<right>" + regex.end
							+ ")", "sgi")
				};
			}
		}; // end of Highlighter

		return sh;
	}(); // end of anonymous function

// CommonJS
typeof (exports) != 'undefined' ? exports.SyntaxHighlighter = SyntaxHighlighter
		: null;
// =====================
// shBrushJScript.js
// =====================
;
(function() {
	// CommonJS
	SyntaxHighlighter = SyntaxHighlighter
			|| (typeof require !== 'undefined' ? require('shCore').SyntaxHighlighter
					: null);

	function Brush() {
		var keywords = 'break case catch continue '
				+ 'default delete do else false  '
				+ 'for function if in instanceof '
				+ 'new null return super switch '
				+ 'this throw true try typeof var while with';

		var r = SyntaxHighlighter.regexLib;

		this.regexList = [ {
			regex : r.multiLineDoubleQuotedString,
			css : 'string'
		}, // double quoted strings
		{
			regex : r.multiLineSingleQuotedString,
			css : 'string'
		}, // single quoted strings
		{
			regex : r.singleLineCComments,
			css : 'comments'
		}, // one line comments
		{
			regex : r.multiLineCComments,
			css : 'comments'
		}, // multiline comments
		{
			regex : /\s*#.*/gm,
			css : 'preprocessor'
		}, // preprocessor tags like #region and #endregion
		{
			regex : new RegExp(this.getKeywords(keywords), 'gm'),
			css : 'keyword'
		} // keywords
		];

		this.forHtmlScript(r.scriptScriptTags);
	}
	;

	Brush.prototype = new SyntaxHighlighter.Highlighter();
	Brush.aliases = [ 'js', 'jscript', 'javascript' ];

	SyntaxHighlighter.brushes.JScript = Brush;

	// CommonJS
	typeof (exports) != 'undefined' ? exports.Brush = Brush : null;
})();
// //====================
// //shBrushXml.js
// //====================
;
(function() {
	// CommonJS
	SyntaxHighlighter = SyntaxHighlighter
			|| (typeof require !== 'undefined' ? require('shCore').SyntaxHighlighter
					: null);

	function Brush() {
		function process(match, regexInfo) {
			var constructor = SyntaxHighlighter.Match, code = match[0], tag = new XRegExp(
					'(&lt;|<)[\\s\\/\\?]*(?<name>[:\\w-\\.]+)', 'xg')
					.exec(code), result = [];

			if (match.attributes != null) {
				var attributes, regex = new XRegExp('(?<name> [\\w:\\-\\.]+)'
						+ '\\s*=\\s*' + '(?<value> ".*?"|\'.*?\'|\\w+)', 'xg');

				while ((attributes = regex.exec(code)) != null) {
					result.push(new constructor(attributes.name, match.index
							+ attributes.index, 'color1'));
					result
							.push(new constructor(attributes.value, match.index
									+ attributes.index
									+ attributes[0].indexOf(attributes.value),
									'string'));
				}
			}

			if (tag != null)
				result.push(new constructor(tag.name, match.index
						+ tag[0].indexOf(tag.name), 'keyword'));

			return result;
		}

		this.regexList = [
				{
					regex : new XRegExp(
							'(\\&lt;|<)\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\](\\&gt;|>)',
							'gm'),
					css : 'color2'
				}, // <![ ... [ ... ]]>
				{
					regex : SyntaxHighlighter.regexLib.xmlComments,
					css : 'comments'
				}, // <!-- ... -->
				{
					regex : new XRegExp(
							'(&lt;|<)[\\s\\/\\?]*(\\w+)(?<attributes>.*?)[\\s\\/\\?]*(&gt;|>)',
							'sg'),
					func : process
				} ];
	}
	;

	Brush.prototype = new SyntaxHighlighter.Highlighter();
	Brush.aliases = [ 'xml', 'xhtml', 'xslt', 'html' ];

	SyntaxHighlighter.brushes.Xml = Brush;

	// CommonJS
	typeof (exports) != 'undefined' ? exports.Brush = Brush : null;
})();
// //===================
// //shBrushCss.js
// //===================
;
(function() {
	// CommonJS
	SyntaxHighlighter = SyntaxHighlighter
			|| (typeof require !== 'undefined' ? require('shCore').SyntaxHighlighter
					: null);

	function Brush() {
		function getKeywordsCSS(str) {
			return '\\b([a-z_]|)'
					+ str.replace(/ /g, '(?=:)\\b|\\b([a-z_\\*]|\\*|)')
					+ '(?=:)\\b';
		}
		;

		function getValuesCSS(str) {
			return '\\b' + str.replace(/ /g, '(?!-)(?!:)\\b|\\b()') + '\:\\b';
		}
		;

		var keywords = 'ascent azimuth background-attachment background-color background-image background-position '
				+ 'background-repeat background baseline bbox border-collapse border-color border-spacing border-style border-top '
				+ 'border-right border-bottom border-left border-top-color border-right-color border-bottom-color border-left-color '
				+ 'border-top-style border-right-style border-bottom-style border-left-style border-top-width border-right-width '
				+ 'border-bottom-width border-left-width border-width border bottom cap-height caption-side centerline clear clip color '
				+ 'content counter-increment counter-reset cue-after cue-before cue cursor definition-src descent direction display '
				+ 'elevation empty-cells float font-size-adjust font-family font-size font-stretch font-style font-variant font-weight font '
				+ 'height left letter-spacing line-height list-style-image list-style-position list-style-type list-style margin-top '
				+ 'margin-right margin-bottom margin-left margin marker-offset marks mathline max-height max-width min-height min-width orphans '
				+ 'outline-color outline-style outline-width outline overflow padding-top padding-right padding-bottom padding-left padding page '
				+ 'page-break-after page-break-before page-break-inside pause pause-after pause-before pitch pitch-range play-during position '
				+ 'quotes right richness size slope src speak-header speak-numeral speak-punctuation speak speech-rate stemh stemv stress '
				+ 'table-layout text-align top text-decoration text-indent text-shadow text-transform unicode-bidi unicode-range units-per-em '
				+ 'vertical-align visibility voice-family volume white-space widows width widths word-spacing x-height z-index';

		var values = 'above absolute all always aqua armenian attr aural auto avoid baseline behind below bidi-override black blink block blue bold bolder '
				+ 'both bottom braille capitalize caption center center-left center-right circle close-quote code collapse compact condensed '
				+ 'continuous counter counters crop cross crosshair cursive dashed decimal decimal-leading-zero default digits disc dotted double '
				+ 'embed embossed e-resize expanded extra-condensed extra-expanded fantasy far-left far-right fast faster fixed format fuchsia '
				+ 'gray green groove handheld hebrew help hidden hide high higher icon inline-table inline inset inside invert italic '
				+ 'justify landscape large larger left-side left leftwards level lighter lime line-through list-item local loud lower-alpha '
				+ 'lowercase lower-greek lower-latin lower-roman lower low ltr marker maroon medium message-box middle mix move narrower '
				+ 'navy ne-resize no-close-quote none no-open-quote no-repeat normal nowrap n-resize nw-resize oblique olive once open-quote outset '
				+ 'outside overline pointer portrait pre print projection purple red relative repeat repeat-x repeat-y rgb ridge right right-side '
				+ 'rightwards rtl run-in screen scroll semi-condensed semi-expanded separate se-resize show silent silver slower slow '
				+ 'small small-caps small-caption smaller soft solid speech spell-out square s-resize static status-bar sub super sw-resize '
				+ 'table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group teal '
				+ 'text-bottom text-top thick thin top transparent tty tv ultra-condensed ultra-expanded underline upper-alpha uppercase upper-latin '
				+ 'upper-roman url visible wait white wider w-resize x-fast x-high x-large x-loud x-low x-slow x-small x-soft xx-large xx-small yellow';

		var fonts = '[mM]onospace [tT]ahoma [vV]erdana [aA]rial [hH]elvetica [sS]ans-serif [sS]erif [cC]ourier mono sans serif';

		this.regexList = [ {
			regex : SyntaxHighlighter.regexLib.multiLineCComments,
			css : 'comments'
		}, // multiline comments
		{
			regex : SyntaxHighlighter.regexLib.doubleQuotedString,
			css : 'string'
		}, // double quoted strings
		{
			regex : SyntaxHighlighter.regexLib.singleQuotedString,
			css : 'string'
		}, // single quoted strings
		{
			regex : /\#[a-fA-F0-9]{3,6}/g,
			css : 'value'
		}, // html colors
		{
			regex : /(-?\d+)(\.\d+)?(px|em|pt|\:|\%|)/g,
			css : 'value'
		}, // sizes
		{
			regex : /!important/g,
			css : 'color3'
		}, // !important
		{
			regex : new RegExp(getKeywordsCSS(keywords), 'gm'),
			css : 'keyword'
		}, // keywords
		{
			regex : new RegExp(getValuesCSS(values), 'g'),
			css : 'value'
		}, // values
		{
			regex : new RegExp(this.getKeywords(fonts), 'g'),
			css : 'color1'
		} // fonts
		];

		this.forHtmlScript({
			left : /(&lt;|<)\s*style.*?(&gt;|>)/gi,
			right : /(&lt;|<)\/\s*style\s*(&gt;|>)/gi
		});
	}
	;

	Brush.prototype = new SyntaxHighlighter.Highlighter();
	Brush.aliases = [ 'css' ];

	SyntaxHighlighter.brushes.CSS = Brush;

	// CommonJS
	typeof (exports) != 'undefined' ? exports.Brush = Brush : null;
})();

// ======================
// shBrushCoffeeScript.js
// ======================
/*
By Rod Vagg <rod@vagg.org> / @rvagg / http://rod.vagg.org
Released under the do-what-you-like-,-attribution-would-be-nice-,-but-please-don't-pass-off-as-your-own-work licence.
*/
SyntaxHighlighter.brushes.CoffeeScript = function() {
  var csKeywords, jsKeywords, keywords;
  jsKeywords = 'if else new return try catch finally throw break continue for in while delete instanceof typeof switch super extends class case default do function var void with const let debugger enum export import native __extends __hasProp';
  csKeywords = 'then unless and or is isnt not of by where when until';
  keywords = jsKeywords + ' ' + csKeywords;
  this.regexList = [
    {
      regex: SyntaxHighlighter.regexLib.singleLinePerlComments,
      css: 'comments'
    }, {
      regex: /\#\#\#[\s\S]*?\#\#\#/gm,
      css: 'comments'
    }, {
      regex: SyntaxHighlighter.regexLib.multiLineDoubleQuotedString,
      css: 'string'
    }, {
      regex: SyntaxHighlighter.regexLib.doubleQuotedString,
      css: 'string'
    }, {
      regex: SyntaxHighlighter.regexLib.singleQuotedString,
      css: 'string'
    }, {
      regex: /\'\'\'[\s\S]*?\'\'\'/gm,
      css: 'string'
    }, {
      regex: /\/\/\/[\s\S]*?\/\/\//gm,
      css: 'string'
    }, {
      regex: /\b([\d]+(\.[\d]+)?|0x[a-f0-9]+)\b/gmi,
      css: 'value'
    }, {
      regex: /(@[\w._]*|this[\w._]*)/g,
      css: 'variable bold'
    }, {
      regex: /(([\w._]+)::([\w._]*))/g,
      css: 'variable bold'
    }, {
      regex: /([\w._]+)\s*(?=\=)/g,
      css: 'variable bold'
    }, {
      regex: /(-&gt;|->|=&gt;|=>|===|==|=|>|&gt;|<|&lt;|\.\.\.|&&|&amp;&amp;|\|\||\!\!|\!|\+\+|\+|--|-|\[|\]|\(|\)|\{|\})|\?|\/|\*|\%/g,
      css: 'keyword'
    }, {
      regex: new RegExp(this.getKeywords(keywords), 'gm'),
      css: 'keyword'
    }
  ];
  return;
};
SyntaxHighlighter.brushes.CoffeeScript.prototype = new SyntaxHighlighter.Highlighter();
SyntaxHighlighter.brushes.CoffeeScript.aliases = ['coffeescript', 'CoffeeScript', 'coffee'];

function render_code(code, type) {
	if (type == "js") {
		var brush = new SyntaxHighlighter.brushes.JScript();
		brush.init({
			toolbar : false
		});
	} else if (type == "css" || type == "less") {
		var brush = new SyntaxHighlighter.brushes.CSS();
		brush.init({
			toolbar : false
		});
	} else if (type == "html") {
		var brush = new SyntaxHighlighter.brushes.Xml();
		brush.init({
			toolbar : false
		});
	} else if (type == "coffeescript") {
		var brush = new SyntaxHighlighter.brushes.CoffeeScript();
		brush.init({
			toolbar : false
		});
	}
	return brush.getHtml(code);
}